const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise {
  constructor(executor) {
    // 1.捕捉执行器抛出的错误
    try {
      executor(this.resolve,this.reject);
    } catch (error) {
      this.reject(error);
    }
  }
  status = PENDING;
  value = undefined;
  reason = undefined;
  successfulCallBack = [];
  loseCallBack = [];
  resolve = (value) => {
    if(this.status != PENDING) return
    this.value = value;
    this.status = FULFILLED;
    while (this.successfulCallBack.length) this.successfulCallBack.shift()();
  }
  reject = (reason) => {
    if(this.status != PENDING) return
    this.reason = reason;
    this.status = REJECTED;
    while (this.loseCallBack.length) this.loseCallBack.shift()();
  }
  // 不管失败和成功都会执行，因为finally后面还可以使用then方法所以要返回一个promise对象，
  // 可以通过调用then而拿到返回值
  finally(callback) {
    // 这里返回的是一个promise对象
    return this.then(value => {
      // 如果test.js中的finally参数内部手动return，那他的返回值的结果就是callback() === test.js中return的那个p1
      // 调用.then(() => value)是为了给finally后面的then返回值，即myPromise中reslove或reject的值，
      // 而并不是return的那个p1promise中的reslove或reject的值
      return MyPromise.resolve(callback()).then(() => value)
    },reason => {
      return MyPromise.resolve(callback()).then(() => reason)
    })
  }
  static resolve(val) {
    // 如果是MyPromise的实例对象就说明是promise对象直接返回
    if (val instanceof MyPromise) return val
    // 不是返回一个promise对象并把传过来的值通过reslove返回出去
    return new MyPromise(function(reslove,reject) {
      reslove(val)
    })
  }
  static all(array) {
    // 返回的数组
    let result = [];
    // 用于判断何时执行addData中resolve的调用时机
    let index = 0;
    return new MyPromise(function(resolve,reject) {
    // 传入索引是为了返回的结果也是按原顺序返回
    function addData(key, val) {
      index ++;
      result[key] = val;
      if (index  === array.length) {
        resolve(result);
      }
    }
      for (let i = 0; i < array.length; i++) {
        const element = array[i];
        if (element instanceof MyPromise) {
          // 是promise对象，需要调用这个promise的then方法查看他的状态，成功状态则继续添加进要返回的数组中，失败的状态就直接调用reject返回错误信息
          element.then(value => {
            addData(i,value)
          }, reason => reject(reason))
        } else {
          // 不是promise对象则直接将结果添加到返回的那个数组中
          addData(i,element)
        }
      }
      // 因为for循环是同步代码，而array中的每一项有可能是一个异步执行的代码，所以for循环执行完，但是因为其中有些项是异步所以会先会继续执行resolve方法，
      // 所以此时result是未添加异步代码执行后返回的结果的，可以把它写在addData中因为addData就是在异步中调用的，
      // 但是这样的话每循环依次就会执行一次resolve是不行的，所以加个index作为标识
      // 
      // resolve(result)
    })
  }
  // catch内部调用的也是then方法只不过没有注册成功的回调而是注册失败的回调
  catch(callback) {
    return this.then(undefined,callback)
  }
  then(successfulCallBack, loseCallBack) {
    // 当调用then方法时没有传入参数那么我们就默认给他一个函数作为参数，这个函数就把resolve或resolve传入的结果直接返回给下一个then
    successfulCallBack = successfulCallBack ? successfulCallBack : (val) => val
    loseCallBack = loseCallBack ? loseCallBack : (rea) => rea
      const promise2 = new Promise((resolve,reject) => {
        if (this.status === FULFILLED) {
          // 2.捕捉成功函数的错误
            setTimeout(() => {
              try {
                let x = successfulCallBack(this.value);
                resolvePromise(promise2,x,resolve,reject)
              } catch (error) {
                reject(error);
              }
            }, 0);
          } else if (this.status === REJECTED) {
            let x = loseCallBack(this.reason);
            reject(x)
            // 3.捕捉失败函数的错误
            setTimeout(() => {
              try {
                let x = loseCallBack(this.reason);
                resolvePromise(promise2,x,resolve,reject)
              } catch (error) {
                reject(error);
              }
            }, 0);
          // 异步操作
          } else {
              // 4.在异步操作中捕获错误
              // 未捕获前的代码
              // this.successfulCallBack.push(successfulCallBack);
              // this.loseCallBack.push(loseCallBack);
              // 修改后的代码
              // 直接传递一个参数无法处理数据，所以返回一个函数
              this.successfulCallBack.push(() => {
                setTimeout(() => {
                  try {
                    let x = successfulCallBack(this.value);
                    resolvePromise(promise2,x,resolve,reject)
                  } catch (error) {
                    reject(error);
                  }
                }, 0);
              });
              this.loseCallBack.push(() => {
                setTimeout(() => {
                  try {
                    let x = loseCallBack(this.reason);
                    resolvePromise(promise2,x,resolve,reject)
                  } catch (error) {
                    reject(error);
                  }
                }, 0);
              });
          }
      });
    return promise2
  }
}

/**
 * 如果then返回Promise对象则调用相应回调，即这个Promise对象的状态是成功就调用成功的回调，状态是失败就调用失败的回调
 * 如果返回的不是Promise对象则调用对应的resolve或reject返回给下一个then
 */
function resolvePromise(promise2,x,resolve,reject) {
  if (promise2 === x) {
    reject(new TypeError("Chaining cycle detected for promise #<Promise>"))
  }
  // 是Promise对象  instanceof 用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链
  if (x instanceof MyPromise) {
    // 调用返回的这个promise的then方法去查看这个promise的状态，如果成功的状态则调用resolve，失败就调用reject
    // x.then((value) => resolve(value), (err) => reject(err))
    // 简写
    x.then(resolve,reject);
  } else {
    // 如果不是Promise对象则直接调用
    resolve(x)
  }
}
module.exports = MyPromise